/**
 *  Copyright (C) 2023 - Fake Inc.
 *
 *  All Rights Reserved.

*/

#ifndef INNO_LIDAR_LOG_H_
#define INNO_LIDAR_LOG_H_

#include <iostream>
#include <memory>
#include <sstream>
#include <string>
#include <utility>
namespace Fake {
enum class InnoLogLevel : int32_t {
  INNO_LOG_LEVEL_TRACE = 0,
  INNO_LOG_LEVEL_DEBUG = 1,
  INNO_LOG_LEVEL_INFO = 2,
  INNO_LOG_LEVEL_WARN = 3,
  INNO_LOG_LEVEL_ERROR = 4,
  INNO_LOG_LEVEL_CRITICAL = 5,
  INNO_LOG_LEVEL_OFF = 6
};
static constexpr uint32_t kLogBufferSize{1024};

template <typename... ARGS_TYPE>
static void inno_log(InnoLogLevel log_lev, const std::string &fmt_str, ARGS_TYPE &&... fmt_args) noexcept {
  std::string tmp_buf(kLogBufferSize, '\0');
  int32_t sp_res{0};

  sp_res = std::snprintf(&tmp_buf[0], tmp_buf.size(), fmt_str.c_str(), std::forward<ARGS_TYPE>(fmt_args)...);
  if (sp_res >= 0) {
    std::cout << "[" << static_cast<int32_t>(log_lev) <<  "]";
    std::cout << tmp_buf << std::endl;
  }
}

template <typename... ARGS_TYPE>
static void inno_log_debug(const std::string &fmt_str, ARGS_TYPE &&... fmt_args) noexcept {
  inno_log(InnoLogLevel::INNO_LOG_LEVEL_DEBUG, fmt_str, std::forward<ARGS_TYPE>(fmt_args)...);
}

template <typename... ARGS_TYPE>
static void inno_log_info(const std::string &fmt_str, ARGS_TYPE &&... fmt_args) noexcept {
  inno_log(InnoLogLevel::INNO_LOG_LEVEL_INFO, fmt_str, std::forward<ARGS_TYPE>(fmt_args)...);
}

template <typename... ARGS_TYPE>
static void inno_log_warning(const std::string &fmt_str, ARGS_TYPE &&... fmt_args) noexcept {
  inno_log(InnoLogLevel::INNO_LOG_LEVEL_WARN, fmt_str, std::forward<ARGS_TYPE>(fmt_args)...);
}

template <typename... ARGS_TYPE>
static void inno_log_error(const std::string &fmt_str, ARGS_TYPE &&... fmt_args) noexcept {
  inno_log(InnoLogLevel::INNO_LOG_LEVEL_ERROR, fmt_str, std::forward<ARGS_TYPE>(fmt_args)...);
}

template <typename... ARGS_TYPE>
static void inno_log_panic(const std::string &fmt_str, ARGS_TYPE &&... fmt_args) {
  inno_log(InnoLogLevel::INNO_LOG_LEVEL_CRITICAL, fmt_str, std::forward<ARGS_TYPE>(fmt_args)...);
  throw std::runtime_error("panic");
}

template <typename... ARGS_TYPE>
static void inno_log_verify(bool check_cond, const std::string &fmt_str, ARGS_TYPE &&... fmt_args) {
  if (!check_cond) {
    inno_log(InnoLogLevel::INNO_LOG_LEVEL_CRITICAL, fmt_str, std::forward<ARGS_TYPE>(fmt_args)...);
    throw std::runtime_error("verify");
  }
}
}  // namespace Fake

#endif
